package org.dromara.admin.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import org.dromara.admin.domain.*;
import org.dromara.admin.domain.bo.AdvanceBillBo;
import org.dromara.admin.domain.vo.AdvanceBillVo;
import org.dromara.admin.domain.vo.ContractBillVo;
import org.dromara.admin.enums.AuditStatus;
import org.dromara.admin.enums.BillStatus;
import org.dromara.admin.enums.BillType;
import org.dromara.admin.service.IAdvanceBillService;
import org.dromara.admin.service.IContractBillService;
import org.dromara.admin.service.IUserDetailService;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.lessor.domain.House;
import org.dromara.system.domain.SysUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.dromara.admin.domain.bo.AdvancePayRecordBo;
import org.dromara.admin.domain.vo.AdvancePayRecordVo;
import org.dromara.admin.mapper.AdvancePayRecordMapper;
import org.dromara.admin.service.IAdvancePayRecordService;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Collection;

/**
 * 垫资账单付款记录Service业务层处理
 *
 * @author Lion Li
 * @date 2025-09-06
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class AdvancePayRecordServiceImpl implements IAdvancePayRecordService {

    private final AdvancePayRecordMapper baseMapper;
    private final IContractBillService contractBillService; // 租金账单信息
    private final IUserDetailService userDetailService;

    @Lazy
    @Autowired
    IAdvanceBillService advanceBillService; // 垫资账单信息


    /**
     * 查询垫资账单付款记录
     *
     * @param id 主键
     * @return 垫资账单付款记录
     */
    @Override
    public AdvancePayRecordVo queryById(Long id){
        return baseMapper.selectVoById(id);
    }

    /**
     * 出租方查询名下垫资账单付款记录列表
     *
     * @param bo 查询条件
     * @return 垫资账单付款记录列表
     */
    @Override
    public TableDataInfo<AdvancePayRecordVo> queryPagePayRecordList(AdvancePayRecordBo bo, PageQuery pageQuery, Long userId) {
        // 使用MPJBaseMapper进行联表查询AdvancePayRecord表、AdvanceBill、SysUser表
        MPJLambdaWrapper<AdvancePayRecord> wrapper = new MPJLambdaWrapper<AdvancePayRecord>()
            .selectAll(AdvancePayRecord.class) // 订单表字段
            .selectAssociation(AdvanceBill.class, AdvancePayRecordVo::getAdvanceBill)
//            .selectAssociation("tu", SysUser.class, AdvancePayRecordVo::getTenantUser)
            .selectAssociation("lu", SysUser.class, AdvancePayRecordVo::getLessorUser)
            .selectAssociation("cu", SysUser.class, AdvancePayRecordVo::getCapitalUser)
            .leftJoin(AdvanceBill.class, AdvanceBill::getId, AdvancePayRecord::getBillId)
            // 租客信息 join
//            .leftJoin(SysUser.class, "tu", on -> on.eq(SysUser::getUserId, AdvancePayRecord::getUserId))
            // 出租方信息 join
            .leftJoin(SysUser.class, "lu", on -> on.eq(SysUser::getUserId, AdvancePayRecord::getLessorUserId))
            // 资方代理信息 join
            .leftJoin(SysUser.class, "cu", on -> on.eq(SysUser::getUserId, AdvancePayRecord::getCapitalUserId))
//            .like(StrUtil.isNotBlank(bo.getUserName()), "tu.user_name", bo.getUserName())
            .like(StrUtil.isNotBlank(bo.getLessorUserName()), "lu.user_name", bo.getLessorUserName())
            .like(StrUtil.isNotBlank(bo.getCapitalUserName()), "cu.user_name", bo.getCapitalUserName());
        wrapper.eq(AdvancePayRecord::getLessorUserId, userId); // 只查当前登录用户的
        Page<AdvancePayRecordVo> result = baseMapper.selectJoinPage(pageQuery.build(), AdvancePayRecordVo.class, wrapper);
        return TableDataInfo.build(result);
    }

    /**
     * 分页查询垫资账单付款记录列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 垫资账单付款记录分页列表
     */
    @Override
    public TableDataInfo<AdvancePayRecordVo> queryPageList(AdvancePayRecordBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<AdvancePayRecord> lqw = buildQueryWrapper(bo);
        Page<AdvancePayRecordVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询符合条件的垫资账单付款记录列表
     *
     * @param bo 查询条件
     * @return 垫资账单付款记录列表
     */
    @Override
    public List<AdvancePayRecordVo> queryList(AdvancePayRecordBo bo) {
        LambdaQueryWrapper<AdvancePayRecord> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<AdvancePayRecord> buildQueryWrapper(AdvancePayRecordBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<AdvancePayRecord> lqw = Wrappers.lambdaQuery();
        lqw.orderByAsc(AdvancePayRecord::getId);
        lqw.eq(bo.getAmount() != null, AdvancePayRecord::getAmount, bo.getAmount());
        lqw.eq(StringUtils.isNotBlank(bo.getType()), AdvancePayRecord::getType, bo.getType());
        lqw.eq(StringUtils.isNotBlank(bo.getPaymentMethod()), AdvancePayRecord::getPaymentMethod, bo.getPaymentMethod());
        lqw.eq(StringUtils.isNotBlank(bo.getStatus()), AdvancePayRecord::getStatus, bo.getStatus());
        lqw.eq(bo.getBillId() != null, AdvancePayRecord::getBillId, bo.getBillId());
        lqw.eq(bo.getOrderId() != null, AdvancePayRecord::getOrderId, bo.getOrderId());
        lqw.eq(StringUtils.isNotBlank(bo.getImages()), AdvancePayRecord::getImages, bo.getImages());
        lqw.eq(bo.getPaymentTime() != null, AdvancePayRecord::getPaymentTime, bo.getPaymentTime());
        lqw.eq(bo.getAuditTime() != null, AdvancePayRecord::getAuditTime, bo.getAuditTime());
        return lqw;
    }

    /**
     * 新增垫资账单付款记录
     *
     * @param bo 垫资账单付款记录
     * @return 是否新增成功
     */
    @Override
    public Boolean insertByBo(AdvancePayRecordBo bo) {
        AdvancePayRecord add = MapstructUtils.convert(bo, AdvancePayRecord.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }

    /**
     * 修改垫资账单付款记录
     *
     * @param bo 垫资账单付款记录
     * @return 是否修改成功
     */
    @Override
    public Boolean updateByBo(AdvancePayRecordBo bo) {
        AdvancePayRecord update = MapstructUtils.convert(bo, AdvancePayRecord.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(AdvancePayRecord entity){
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 校验并批量删除垫资账单付款记录信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     * @return 是否删除成功
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if(isValid){
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteByIds(ids) > 0;
    }

    /**
     * 创建垫资账单付款记录信息
     *
     * @param advanceBill 垫资账单信息
     * @return 是否成功
     */
    @Override
    public Boolean creatByAdvanceBillBo(AdvanceBillBo advanceBill) {
        AdvancePayRecord advancePayRecord = new AdvancePayRecord();
        advancePayRecord.setAmount(advanceBill.getAmountReality());
        advancePayRecord.setType(BillType.PAYMENT.getCode());
        advancePayRecord.setPaymentMethod(advanceBill.getPaymentMethod());
        advancePayRecord.setStatus(AuditStatus.PENDING.getCode());
        advancePayRecord.setBillId(advanceBill.getId());
        advancePayRecord.setOrderId(advanceBill.getOrderId());
        advancePayRecord.setCapitalUserId(advanceBill.getCapitalUserId());
        advancePayRecord.setLessorUserId(advanceBill.getLessorUserId());
        advancePayRecord.setImages(advanceBill.getImages());
        advancePayRecord.setPaymentTime(new Date());
        boolean flag = baseMapper.insert(advancePayRecord) > 0;
        if (!flag) {
            throw new ServiceException("创建垫资付款记录异常！");
        }
        return Boolean.TRUE;
    }

    /**
     * 出租方审核垫资付款记录
     * @param bo
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean reviewCapitalPay(AdvancePayRecordBo bo) {
        AdvancePayRecord advancePayRecordDB = baseMapper.selectById(bo.getId());
        if (BeanUtil.isEmpty(advancePayRecordDB)) {
            throw new ServiceException("未找到该笔垫资付款记录!");
        }
        AdvanceBillVo advanceBillVo = advanceBillService.queryById(advancePayRecordDB.getBillId());
        if (BeanUtil.isEmpty(advanceBillVo)) {
            throw new ServiceException("未找到该笔付款记录的垫资账单信息!");
        }
        if (!LoginHelper.getUserId().equals(advancePayRecordDB.getLessorUserId())){
            throw new ServiceException("您没有权限审核该笔垫资付款记录!");
        }

        // 判断垫资付款记录是否已经审核过
        if (!AuditStatus.PENDING.getCode().equals(advancePayRecordDB.getStatus())){
            throw new ServiceException("该笔垫资付款记录已经审核过了!");
        }

        // 审核失败
        if (AuditStatus.REJECTED.getCode().equals(bo.getStatus())){
            advanceBillVo.setRemarks(bo.getRemarks());
            advanceBillVo.setBillStatus(BillStatus.UNPAID.getCode());
        }

        // 审核通过
        if (AuditStatus.APPROVED.getCode().equals(bo.getStatus())){
            // 修改租金账单为已垫资
            contractBillService.handle6ListByOrderId(advancePayRecordDB.getOrderId());
        }
        // 修改垫资账单状态
        advanceBillVo.setAuditStatus(bo.getStatus());
        advanceBillService.reviewUpdate(advanceBillVo);
        // 修改支付记录状态
        advancePayRecordDB.setStatus(bo.getStatus());
        advancePayRecordDB.setAuditTime(new Date());
        return baseMapper.updateById(advancePayRecordDB) > 0;

    }
}
